﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;

namespace NuMvvm.Commands
{
    /// <summary>
    /// Delegate command
    /// </summary>
    public class DelegateCommand : ICommand
    {
        private readonly Func<bool> _canExecute;
        private readonly Action _execute;

        public DelegateCommand(Action execute)
        {
            _execute = execute;
            _canExecute = null;
        }

        public DelegateCommand(Action execute,
                               Func<bool> canExecute)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

        public bool CanExecute()
        {
            if (_canExecute == null)
            {
                return true;
            }

            return _canExecute();
        }

        public void Execute()
        {
            _execute();
        }

        public void RaiseCanExecuteChanged()
        {
            if (CanExecuteChanged != null)
                CanExecuteChanged(this, EventArgs.Empty);
        }

        #region Implements ICommand 

        public event EventHandler CanExecuteChanged;

        bool ICommand.CanExecute(object parameter)
        {
            return CanExecute();
        }

        void ICommand.Execute(object parameter)
        {
            Execute();
        }

        #endregion

        public static DelegateCommand Create(Action execute)
        {
            return new DelegateCommand(execute);
        }

        public static DelegateCommand Create(Action execute, Func<bool> canExecute)
        {
            return new DelegateCommand(execute, canExecute);
        }

        public static DelegateCommand<T> Create<T>(Action<T> execute)
        {
            return new DelegateCommand<T>(execute);
        }

        public static DelegateCommand<T> Create<T>(Action<T> execute, Func<T, bool> canExecute)
        {
            return new DelegateCommand<T>(execute, canExecute);
        }

        public static AsyncDelegateCommand Create(Func<CancellationToken, Task> execute)
        {
            return new AsyncDelegateCommand(execute);
        }

        public static AsyncDelegateCommand Create(Func<CancellationToken, Task> execute, Func<CancellationToken, Task<bool>> canExecute)
        {
            return new AsyncDelegateCommand(execute, canExecute);
        }

        public static AsyncDelegateCommand<T> Create<T>(Func<T, CancellationToken, Task> execute)
        {
            return new AsyncDelegateCommand<T>(execute);
        }

        public static AsyncDelegateCommand<T> Create<T>(Func<T, CancellationToken, Task> execute, Func<T, CancellationToken, Task<bool>> canExecute)
        {
            return new AsyncDelegateCommand<T>(execute, canExecute);
        }
    }
}
